home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / MODEM.C < prev    next >
Text File  |  1993-10-09  |  11KB  |  491 lines

  1. /* Automatic SLIP/PPP line dialer.
  2.  *
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  *
  5.  *    Mar '91    Bill Simpson & Glenn McGregor
  6.  *        completely re-written;
  7.  *        human readable control file;
  8.  *        includes wait for string, and speed sense;
  9.  *        dials immediately when invoked.
  10.  *    May '91 Bill Simpson
  11.  *        re-ordered command line;
  12.  *        allow dial only;
  13.  *        allow inactivity timeout without ping.
  14.  *    Sep '91 Bill Simpson
  15.  *        Check known DTR & RSLD state for redial decision
  16.  *    Mar '92    Phil Karn
  17.  *        autosense modem control stuff removed
  18.  *        Largely rewritten to do demand dialing
  19.  */
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include "global.h"
  23. #include "config.h"
  24. #ifdef MODEM
  25. #include "mbuf.h"
  26. #include "timer.h"
  27. #include "proc.h"
  28. #include "iface.h"
  29. #include "netuser.h"
  30. #include "n8250.h"
  31. #include "asy.h"
  32. #include "tty.h"
  33. #include "session.h"
  34. #include "socket.h"
  35. #include "cmdparse.h"
  36. #include "devparam.h"
  37. #include "icmp.h"
  38. #include "files.h"
  39. #include "trace.h"
  40. #include "pktdrvr.h"
  41. #include "modem.h"
  42. #include "usock.h"
  43. #include "commands.h"
  44.  
  45. #define MIN_INTERVAL    5L
  46.  
  47. unsigned Tiptimeout = 180;    /* Default tip inactivity timeout (seconds) */
  48.  
  49. char TActive[] = "Tip or Dialer already active on %s\n";
  50.  
  51. static struct iface * near
  52. check_if(char *s)
  53. {
  54.     struct iface *ifp;
  55.  
  56.     if((ifp = if_lookup(s)) == NULLIF) {
  57.         tprintf(Badif,s);
  58.         return NULLIF;
  59.     }
  60.     if(ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp) {
  61.         tprintf(Badasy,s);
  62.         return NULLIF;
  63.     }
  64.     return ifp;
  65. }
  66.  
  67. static int
  68. dodial_control(int argc,char **argv,void *p)
  69. {
  70.     struct iface *ifp = p;
  71.     int param;
  72.  
  73.     if(ifp->ioctl == NULL || (param = devparam(argv[1])) == -1) {
  74.         return -1;
  75.     }
  76.     (*ifp->ioctl)(ifp,param,TRUE,atol(argv[2]));
  77.     return 0;
  78. }
  79.  
  80. static int
  81. dodial_send(int argc,char **argv,void *p)
  82. {
  83.     struct iface *ifp = p;
  84.     struct mbuf *bp;
  85.  
  86.     if(argc > 2) {
  87.         /* Send characters with inter-character delay
  88.          * (for dealing with prehistoric Micom switches that
  89.          * can't take back-to-back characters...yes, they
  90.          * still exist.)
  91.          */
  92.         char *cp;
  93.         int32 cdelay = atol(argv[2]);
  94.  
  95.         for(cp = argv[1]; *cp != '\0'; cp++) {
  96.             bp = qdata(cp,1);
  97.             enqueue(&Asy[ifp->dev].sndq,bp);
  98. /*            asy_send(ifp->dev,bp);    */
  99.             pause(cdelay);
  100.         }
  101.     } else {
  102.         bp = qdata(argv[1],strlen(argv[1]));
  103.         dump(ifp,IF_TRACE_OUT,-1,bp);
  104.         enqueue(&Asy[ifp->dev].sndq,bp);
  105. /*        asy_send(ifp->dev,bp);    */
  106.     }
  107.     return 0;
  108. }
  109.  
  110. static int
  111. dodial_speed(int argc,char **argv,void *p)
  112. {
  113.     struct iface *ifp = p;
  114.  
  115.     return asy_speed(ifp->dev,(int16)atol(argv[1]));
  116. }
  117.  
  118. static int
  119. dodial_wait(int argc,char **argv,void *p)
  120. {
  121.     struct iface *ifp = p;
  122.     int c = -1;
  123.     int32 timeout = atol(argv[1]);
  124.  
  125.     if(!timeout) {
  126.         timeout = 10;
  127.         argc = 2;
  128.     }
  129.     alarm(timeout);
  130.  
  131.     if(argc == 2) {
  132.         while((c = get_asy(ifp->dev)) != -1) {
  133. /*            usputc(Curproc->output,c);    */
  134.         }
  135. /*        usflush(Curproc->output);    */
  136.         alarm(0);
  137.         return 0;
  138.     } else {
  139.         char *cp = argv[2];
  140.  
  141.         while(*cp != '\0' && (c = get_asy(ifp->dev)) != -1) {
  142. /*            usputc(Curproc->output,c);    */
  143.  
  144.             if(*cp++ != c) {
  145.                 cp = argv[2];
  146.             }
  147.         }
  148. /*        usflush(Curproc->output);    */
  149.  
  150.         if(argc > 3) {
  151.             if(stricmp(argv[3],"speed") == 0 ) {
  152.                 int16 speed = 0;
  153.  
  154.                 while((c = get_asy(ifp->dev)) != -1) {
  155. /*                    usputc(Curproc->output,c);    */
  156.  
  157.                     if(isdigit(c)) {
  158.                         speed *= 10;
  159.                         speed += c - '0';
  160.                     } else {
  161.                         alarm(0);
  162.                         return asy_speed(ifp->dev,speed);
  163.                     }
  164.                 }
  165. /*                usflush(Curproc->output);    */
  166.             } else {
  167.                 alarm(0);
  168.                 return -1;
  169.             }
  170.         }
  171.     }
  172.     alarm(0);
  173.     return (c == -1);
  174. }
  175.  
  176. /* execute dialer commands
  177.  * returns: -1 fatal error, 0 OK, 1 try again
  178.  */
  179. int
  180. redial(struct asy *asyp,int flag)
  181. {
  182.     char inbuf[MAXPATH], intmp[MAXPATH], *file = flag ? asyp->actfile : asyp->dropfile;
  183.     FILE *fp;
  184.     int result = 0, (*rawsave) __ARGS((struct iface *,struct mbuf *));
  185.     static char Dial[] = "\nDialing on %s%s\n";
  186.  
  187.     static struct cmds dial_cmds[] = {
  188.         {"control",    dodial_control,    0, 2, "control up|down"},
  189.         {"send",    dodial_send,    0, 2, "send \"string\" [<msecs>]"},
  190.         {"speed",    dodial_speed,    0, 2, "speed <bps>"},
  191.         {"wait",    dodial_wait,    0, 2, "wait <msecs> [\"string\" [speed]]"},
  192.         {NULLCHAR,    NULLFP,            0, 0, "Unknown command"},
  193.     };
  194.     if((fp = Fopen(file,READ_TEXT,0,1)) == NULLFILE) {
  195.         return -1;
  196.     }
  197.     /* Save output handler and temporarily redirect output to null */
  198.     if(asyp->iface->raw == bitbucket) {
  199.         tprintf(TActive,asyp->iface->name);
  200.         return -1;
  201.     }
  202.     tprintf(Dial,asyp->iface->name,"");
  203.  
  204.     /* Save output handler and temporarily redirect output to null */
  205.     rawsave = asyp->iface->raw;
  206.     asyp->iface->raw = bitbucket;
  207.  
  208.     /* Suspend the packet input driver. Note that the transmit driver
  209.      * is left running since we use it to send buffers to the line.
  210.      */
  211.     suspend(asyp->iface->proc);
  212.  
  213.     while(fgets(inbuf,MAXPATH,fp) != NULLCHAR) {
  214.         rip(inbuf);
  215.         strcpy(intmp,inbuf);
  216.  
  217.         log(-1,9984,"%s: %s",asyp->iface->name,intmp);
  218.  
  219.         if((result = cmdparse(dial_cmds,inbuf,asyp->iface)) != 0) {
  220.             tprintf("ERROR line: %s\n",intmp);
  221.             break;
  222.         }
  223.     }
  224.     Fclose(fp);
  225.  
  226.     if(result == 0) {
  227.         asyp->iface->lastsent = asyp->iface->lastrecv = secclock();
  228.     }
  229.     asyp->iface->raw = rawsave;
  230.     resume(asyp->iface->proc);
  231.     tprintf(Dial,asyp->iface->name," complete");
  232.  
  233.     return result;
  234. }
  235.  
  236. static void
  237. dropit(int i,void *p,void *u)
  238. {
  239.     struct iface *ifp = p;
  240.     struct asy *ap = &Asy[ifp->dev];
  241.  
  242.     if(ap->msr & MSR_RLSD) {
  243.         ap->localdrops++;
  244.         redial(ap,0);            /* Drop only if still up */
  245.     }
  246. }
  247.  
  248. /* Called when idle line timer expires -- executes script to drop line */
  249. static void
  250. dropline(void *p)
  251. {
  252.     /* Fork this off to prevent wedging the timer task */
  253.     newproc("dropit",768,dropit,0,p,NULL,0);
  254. }
  255.  
  256. /* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
  257.  *    <iface>        must be asy type
  258.  *    <filename>    contains commands which are executed.
  259.  *            missing: kill outstanding dialer.
  260.  *    <seconds>    interval to check for activity on <iface>.
  261.  *    <pings>     number of missed pings before redial.
  262.  *    <hostid>    interface to ping.
  263.  */
  264. int
  265. dodial(int argc,char **argv,void *p)
  266. {
  267.     struct iface *ifp;
  268.     struct asy *ap;
  269.     int32 timeout;
  270.  
  271.     if((ifp = check_if(argv[1])) == NULLIF) {
  272.         return 1;
  273.     }
  274.     ap = &Asy[ifp->dev];
  275.  
  276.     if(!ap->rlsd){
  277.         tputs("Must set 'r' flag at attach time\n");
  278.         return -1;
  279.     }
  280.     if(argc < 3) {
  281.         tprintf("%s: %s, idle timer %ld/%ld secs\n",
  282.             ifp->name,
  283.             (ap->msr & MSR_RLSD) ? "UP" : "DOWN",
  284.             read_timer(&ap->idle)/1000L,
  285.             dur_timer(&ap->idle)/1000L);
  286.  
  287.         if(ap->actfile != NULLCHAR) {
  288.             tprintf("Up script: %s\n",ap->actfile);
  289.         }
  290.         if(ap->dropfile != NULLCHAR) {
  291.             tprintf("Down script: %s\n",ap->dropfile);
  292.         }
  293.         tprintf("Calls originated/timed out %ld/%ld, Carrier up/down transitions %ld/%ld\n",
  294.             ap->originates,ap->localdrops,ap->answers,ap->remdrops);
  295.         return 0;
  296.     }
  297.     if((timeout = atol(argv[2]) * 1000L) != 0 && argc < 5) {
  298.         tputs("Usage: dial <iface> <timeout> <raisefile> <dropfile>\n"
  299.               "       dial <iface> 0\n");
  300.         return -1;
  301.     }
  302.     stop_timer(&ap->idle);
  303.     set_timer(&ap->idle,0);
  304.  
  305.     if(ap->actfile != NULLCHAR) {
  306.         xfree(ap->actfile);
  307.         ap->actfile = NULLCHAR;
  308.     }
  309.     if(ap->dropfile != NULLCHAR){
  310.         xfree(ap->dropfile);
  311.         ap->dropfile = NULLCHAR;
  312.     }
  313.     if(timeout != 0) {
  314.         ap->actfile = mxallocw(MAXPATH);
  315.         sprintf(ap->actfile,"%s/%s",EtcRoot,argv[3]);
  316.         ap->dropfile = mxallocw(MAXPATH);
  317.         sprintf(ap->dropfile,"%s/%s",EtcRoot,argv[4]);
  318.  
  319.         ap->idle.func = dropline;
  320.         ap->idle.arg = ifp;
  321.         set_timer(&ap->idle,timeout);
  322.         start_timer(&ap->idle);
  323.     }
  324.     return 0;
  325. }
  326.  
  327. /* Input process */
  328. void
  329. tip_in(int dev,void *n1,void *n2)
  330. {
  331.     struct tipcb *tip = n1;
  332.     struct mbuf *bp;
  333.     char *buf[2], line[LINELEN];
  334.     int c, pos = 0;
  335.  
  336.     while((c = get_asy(dev)) != -1){
  337.         int ret = 0;
  338.         Asy[dev].iface->lastrecv = secclock();
  339.  
  340.         if(tip->echo == WONT) {
  341.             switch(c) {
  342.             case 18:    /* CTRL-R */
  343.                 bp = pushdown(qdata(line,pos),4);
  344.                 memcpy(bp->data,"^R\r\n",4);
  345.                 ret = 1;
  346.                 break;
  347.             case 0x7f:    /* DEL */
  348.             case '\b':
  349.                 bp = NULLBUF;
  350.                 if(pos) {
  351.                     --pos;
  352.                     bp = qdata("\b \b",3);
  353.                 }
  354.                 ret = 1;
  355.                 break;
  356.             case '\r':
  357.                 c = '\n';    /* CR => NL */
  358.             case '\n':
  359.                 bp = qdata("\r\n",2);
  360.                 break;
  361.             default:
  362.                 bp = pushdown(NULLBUF,1);
  363.                 *bp->data = c;
  364.                 break;
  365.             }
  366.             enqueue(&Asy[dev].sndq,bp);
  367. /*            asy_send(dev,bp);    */
  368.             tip->iface->lastsent = secclock();
  369.  
  370.             if(ret) {
  371.                 continue;
  372.             }
  373.         }
  374.         line[pos++] = c;
  375.  
  376.         if(pos == LINELEN - 1 || tip->echo == WILL || c == '\n') {
  377.             line[pos] = '\0';
  378.             pos = 0;
  379.             usputs(tip->s,line);
  380.         }
  381.     }
  382.     /* get_asy() failed, terminate */
  383.     close_s(tip->s);
  384.     tip->in = tip->proc;
  385.     tip->proc = Curproc;
  386.     buf[1] = Asy[dev].iface->name;
  387.     tip0(2,buf,NULL);
  388. }
  389.  
  390. /* Output process, DTE version */
  391. static void
  392. tip_out(int dev,void *n1,void *n2)
  393. {
  394.     int c;
  395.  
  396.     while((c = recvchar(Curproc->input)) != EOF) {
  397.         struct mbuf *bp = pushdown(NULLBUF,1);
  398.  
  399.         if(c != '\n') {
  400.             *bp->data = c;
  401.         } else {
  402.             *bp->data = '\r';
  403.         }
  404.         enqueue(&Asy[dev].sndq,bp);
  405. /*        asy_send(dev,bp);    */
  406.         Asy[dev].iface->lastsent = secclock();
  407.     }
  408. }
  409.  
  410. /* Execute user tip command */
  411. int
  412. dotip(int argc,char **argv,void *p)
  413. {
  414.     struct session *sp;
  415.     struct iface *ifp;
  416.     char *ifn;
  417.     int c, (*rawsave) __ARGS((struct iface *,struct mbuf *));
  418.  
  419.     if((ifp = check_if(argv[1])) == NULLIF) {
  420.         return -1;
  421.     }
  422.     if(ifp->raw == bitbucket) {
  423.         tprintf(TActive,argv[1]);
  424.         return -1;
  425.     }
  426.     /* Allocate a session descriptor */
  427.     if((sp = newsession(argv[1],TIP,SWAP)) == NULLSESSION){
  428.         tputs(Nosess);
  429.         keywait(NULLCHAR,1);
  430.         return 1;
  431.     }
  432.     /* Save output handler and temporarily redirect output to null */
  433.     rawsave = ifp->raw;
  434.     ifp->raw = bitbucket;
  435.  
  436.     /* Suspend the packet input driver. Note that the transmit driver
  437.      * is left running since we use it to send buffers to the line.
  438.      */
  439.     suspend(ifp->proc);
  440.  
  441.     /* Put tty into raw mode */
  442.     sp->ttystate.echo = sp->ttystate.edit = 0;
  443.     sockmode(sp->output,SOCK_BINARY);
  444.  
  445.     /* Now fork into two paths, one rx, one tx */
  446.     ifn = if_name(ifp," tip out");
  447.     sp->proc1 = newproc(ifn,256,tip_out,ifp->dev,NULL,NULL,0);
  448.     xfree(ifn);
  449.  
  450.     ifn = if_name(ifp," tip in");
  451.     sprintf(Curproc->name,"%.16s",ifn);
  452.     xfree(ifn);
  453.  
  454.     /* bring the line up (just in case) */
  455.     if(ifp->ioctl != NULL) {
  456.         (*ifp->ioctl)(ifp,PARAM_UP,TRUE,0);
  457.     }
  458.     while((c = get_asy(ifp->dev)) != -1) {
  459.         usputc(Curproc->output,c);
  460.     }
  461.     usflush(Curproc->output);
  462.  
  463.     killproc(sp->proc1);
  464.     sp->proc1 = NULLPROC;
  465.     ifp->raw = rawsave;
  466.     resume(ifp->proc);
  467.  
  468.     keywait(NULLCHAR,1);
  469.     freesession(sp);
  470.     return 0;
  471. }
  472.  
  473. void
  474. tipidle(void *t)
  475. {
  476.     static char *msg = "You have been idle too long. Please hang up.\r\n";
  477.     struct tipcb *tip = (struct tipcb *)t;
  478.  
  479.     if(secclock() - tip->iface->lastrecv < Tiptimeout) {
  480.         set_timer(&tip->timer,(Tiptimeout-secclock() * tip->iface->lastrecv) * 1000);
  481.         start_timer(&tip->timer);
  482.         return;
  483.     }
  484.     enqueue(&Asy[tip->iface->dev].sndq,qdata(msg,strlen(msg)));
  485. /*    asy_send(tip->iface->dev,qdata(msg,strlen(msg)));    */
  486.     tip->iface->lastsent = secclock();
  487.     close_s(tip->s);
  488. }
  489. #endif /* MODEM */
  490.  
  491.